The present invention relates to microprocessors for computers and other electronic devices, and especially relates to multi-tasking type microprocessors and methods of performing such multi-tasking.
Specifically, the invention addresses a method of significantly faster task switching and interrupt processing in a particular family of multi-tasking microprocessors.
A commercially available set of microprocessors, the Intel Corporation i960 family (also known as 80960), is an example of multi-tasking type microprocessors. The current i960 family includes the i960KA, i960KB, i960SA, i960SB and i960CA microprocessors, among others. These microprocessors are structured to have consistent software interfaces across multiple generations of microprocessor implementations of a common architecture.
These microprocessor chips contain an execution unit, an optional floating-point unit, and on-chip instruction cache. They also include a register-oriented instruction set, multiple register sets, a procedure call mechanism, and fundamental mechanisms for handling interrupts and faults.
Each microprocessor chip provides a single set of 16 "global registers" and multiple sets of 16 "local registers". The global registers are primarily used as general-purpose registers, and must be preserved across procedure boundaries. A "procedure" is a function callable from within a software program. The local registers provide storage for data variables that are local to an active procedure.
The i960's standard procedure call/return mechanism simplifies procedure calls, and provides a convenient means of preserving local procedure variables. A dedicated region of memory is assigned to a "procedure stack". This stack contains contiguous stack frames, one frame for each active procedure within a task. A frame provides storage area for local registers. Each time a procedure call is made, a new stack frame for the called procedure is allocated just beyond the current frame. This frame then becomes the current frame. A set of local registers is automatically allocated for the called procedure, and the local register set for the calling procedure is saved. When the called procedure executes a return, the current stack frame is deallocated, the previous stack frame is restored, and the local register set for the calling procedure is restored.
The i960family of microprocessors uses three registers to maintain stack frame linkage information. These are a frame pointer which contains the address of the current stack frame, a stack pointer which contains the address of the next unused byte of the current stack frame, and a previous frame pointer which contains the address of the previous stack frame.
This microprocessor contains a control register, called the "process-controls register", which is used to store information about the current status of the processor. A single bit of this register, called the "state flag", reflects the state of the processor. When this bit is cleared (0), the processor is in "executing" state (i.e., it is currently executing a program). When this bit is set (1), the processor is in "interrupted" state (i.e., the processor has been interrupted so that it can service an interrupt request). This state flag is changed automatically by the processor as the processor switches between executing and interrupted state. The microprocessor also contains another control register, called the "arithmetic-controls register", which is used to store status and control information relating to arithmetic operations.
The Intel "80960KB Programmer's Reference Manual" (Order Number 270567-002), section "PROCESSOR AND PROGRAM STATES", page 7-6, recites: "In the executing state, the processor is executing the program. If the processor is interrupted while in the executing state, it saves the current state of the program, switches to the interrupted state, and services the interrupt. Upon returning from the interrupt handler, the processor resumes work on the program." This statement reflects the hardware design of the i960 processors, whereby the definition of the processor state is "executing" for task execution, and "interrupted" for interrupt servicing, and the state flag itself is modified by the processor as it switches between the two states.
The same manual, section "PROCESS CONTROLS", page 7-4, recites: "The state flag determines the state of the program. The encoding of this bit is shown in Table 7-1. This bit tells software whether the processor is currently executing a program (0) or has been interrupted so the (sic) it can service an interrupt (1)." This statement reiterates the fact that the state flag is totally under control of the processor, but may be read by software.
At no time has the manufacturer suggested that the processor state flag can or should be directly altered by the software, nor did the manufacturer ever intend that the processor state flag be used in any other mode than the "executing" state for task execution and the "interrupted" state for interrupt processing.
This microprocessor architecture includes a priority-based interrupt mechanism. Interrupt requests are generally sent to the microprocessor from an external source, often to request I/O (input/output) services. An "interrupt" breaks the control flow of a currently operating program so that the microprocessor can handle a more urgent job. The receipt of an interrupt signal causes an interruption of the program and switches the microprocessor into the interrupted state. Upon completion of servicing an interrupt, the microprocessor switches back into executing state, and resumes processing of the interrupted program.
Each interrupt request has associated with it an 8-bit interrupt vector number which points to a vector entry in the interrupt table. The vector entry contains the address of a specific software interrupt handler. An "interrupt handler" performs the specific action associated with a particular interrupt request.
In addition to the procedure stack, this microprocessor architecture has a single dedicated area of memory assigned to an "interrupt stack". This stack has the same structure as the procedure stack, in that it consists of contiguous stack frames. Interrupt records, which contain the state of interrupted programs, are also stored on the interrupt stack. Each interrupt stack frame has associated with it a single interrupt record.
Each interrupt has a programmably assigned priority; priorities range from 0 to 31, with 31 being the highest priority. If the interrupt priority is 31, or is higher than the processor's current priority, an interrupt handler is invoked. Otherwise, the interrupt is posted for later processing.
Whenever this microprocessor receives an interrupt signal, it compares the priority of the interrupt request with the processor's current priority to determine whether to service the interrupt immediately. If the interrupt priority is higher than that of the processor, the processor services the interrupt immediately. If the interrupt priority is equal to or less than that of the processor, the processor records the new interrupt in the pending interrupt field of an interrupt table, and the servicing of the interrupt is delayed.
When this microprocessor receives a higher priority interrupt while it is in executing state (i.e., executing a task), it performs the following actions to service the interrupt:
(1) It switches from the current procedure stack to the interrupt stack, and the start of the interrupt stack becomes the current stack pointer for the processor; PA0 (2) It saves the current state of the process-controls register, the arithmetic-controls register, and the current interrupt vector number in an interrupt record on the current stack, which has become the interrupt stack; PA0 (3) For certain microprocessors in the i960 family, if the execution of an instruction was suspended, a resumption record for the suspended instruction is included in the interrupt record, and a resume flag in the saved process controls field is set; PA0 (4) It sets the state flag in the process-controls register to "interrupted", the execution mode to "supervisor", and the priority field to the priority of the interrupt; PA0 (5) It clears a trace-fault-pending flag and a trace-enable flag in the process-controls register; and PA0 (6) It performs an implicit call to the interrupt handler. The address for the procedure that is called is that which is specified in an interrupt table for the specified interrupt vector. A new frame for the interrupt handler is allocated on the current stack, and the current frame pointer is loaded into a global register. A new set of local registers is allocated for the interrupt handler. Upon entry to the interrupt handler, the processor is in interrupted state and supervisor mode. PA0 (1) It copies the arithmetic controls information from the interrupt record into the arithmetic-controls register; PA0 (2) It copies the process controls information into the process-controls register whereby this action restores the processor stare to executing; PA0 (3) If a resume flag of the process-controls register is set, it copies the resumption record from the interrupt record to the microprocessor Processor Control Block (PRCB); PA0 (4) It deallocates the current interrupt stack frame and interrupt record from the interrupt stack, and releases the allocated set of local registers; PA0 (5) It checks the interrupt table for pending interrupts that are higher than the priority of the interrupt which the processor is executing. If a higher priority pending interrupt is found, it is handled as if the interrupt occurred at this point; and PA0 (6) It then performs a return operation. This will cause the processor to switch back to the stack frame on the procedure stack that the processor was using prior to the interrupt, restore the local register set for that procedure, and resume the interrupted procedure. The processor has now returned to "executing" state.
Once the microprocessor has completed the interrupt processing, it performs the following action on the return from the interrupt:
If the processor receives an interrupt while it is in the interrupted state (i.e., the processor is servicing another interrupt), and the new interrupt has a higher priority than the interrupt currently being serviced, the processor performs the same action as that described above for the executing state except that the processor does not need to switch stacks, since the interrupt stack will already be in use. A new interrupt record and interrupt frame are created on the current stack, which is still the interrupt stack, immediately following the frame for the interrupted interrupt handler. On the return from the current interrupt handler to the previous interrupt handler, the processor deallocates the current stack frame and interrupt record, and remains on the interrupt stack.
The manufacturer, in its previously quoted reference manual at the section on "INTERRUPT HANDLING ACTIONS", at pages 8-4 through 8-6, has recited: "When the processor receives an interrupt, it handles it automatically. The processor takes care of saving the processor state, calling the interrupt-handler routine, and restoring the processor state once the interrupt has been serviced. Software support is not required. . . . When the processor receives an interrupt while it is in executing state (i.e., executing a program), it performs the following actions to service the interrupt; this procedure is the same regardless of whether the processor is in the user or the supervisor mode when the interrupt occurs: 1. The processor switches to the interrupt stack . . . 4. The processor allocates a new frame on the interrupt stack . . . 5. The processor switches to the interrupted state. . . . Once the processor has completed the interrupt procedure, it performs the following action on the return: . . . 4. The processor deallocates the current stack frame and interrupt record from the i-interrupt stack and switches to the local stack or the supervisor stack (whichever one it was using when it was interrupted). . . . 6. Assuming that there are no pending interrupts to be serviced, the processor switches to the executing state and resumes work on the program. . . . If the processor receives an interrupt while it is servicing another interrupt, . . . The interrupt record is saved on the top of the interrupt stack, prior to the new frame that is created for use in servicing the new interrupt. On the return from the current interrupt handler to the previous interrupt handler, the processor deallocates the current stack frame and interrupt record, and stays on the interrupt stack."
Another member of the common i960family is the i960CA microprocessor. The Intel "80960CA User's Manual" (Order Number 270710-001) at the section "THE 80960 INTERRUPT MODEL", pages 6-2 through 6-9, recites: "The architecture defines two data structures to support interrupt processing: the interrupt table and the interrupt stack. . . . The method that the processor uses to service an interrupt depends on the state the processor is in when it receives the interrupt. If the processor is executing a background task when an interrupt request is to be serviced, the interrupt context switch must change stacks to the interrupt stack. This is called an executing-state interrupt. If the processor is already executing an interrupt handler, no stack switch is required since the interrupt stack will already be in use. This is called an interrupted-state interrupt."
The manufacturer has constructed its i960 series architecture so that all interrupt records and interrupt frames are placed on the interrupt stack, programs are executed in processor "executing" state, interrupts are serviced in processor "interrupted" state, and that an executing-state interrupt causes a switch to the interrupt stack.
A major aspect of prior microprocessor multi-tasking architecture, including that of the i960 family, is the presence of mechanisms related to task management. The task-management mechanisms use synchronization logic to provide correct behavior in the event of multiple concurrent tasks. Task management is performed with two operations: (1) suspend task and save task context, and (2) restore task context and resume task. This mechanism allows an operating system kernel to switch tasks explicitly.
In a multi-tasking, real-time system, reevaluation of task priorities for scheduling is often done following an interrupt. It often becomes mandatory to preempt the currently active task in favor of a higher priority task which has been waiting for an event. This means that upon completion of interrupt processing, an operating system kernel must prevent the normal resumption of the interrupted task. After the higher priority task has completed its processing, the context of the task which had been interrupted, and then preempted, can be restored and that task may be resumed.
When a preemption is to occur at the completion of interrupt processing, the processor switches from interrupted to executing state when it begins the execution of the higher priority task. The context status of the task which had been interrupted exists in the interrupt record and frame of the interrupt handler at the beginning of the interrupt stack. If an interrupt should occur while the higher priority task is executing, the processor will then switch to interrupted state, and create a new interrupt frame and record at the beginning of the interrupt stack, thus overwriting the previous interrupt record and frame for the task that had been preempted. The solution presented by the i960 series manufacturer is to have the operating system kernel copy the context for the interrupted task from the interrupt stack to another temporary holding area of memory prior to preempting an interrupted task. This area of memory must be unique to the interrupted task, and may not be shared by any other task.
The i960 series manufacturer's recommended, expressly stated established procedure is to create an array of dedicated task control blocks, one per task. The task context information which must be copied from the interrupt record to the task control block includes the process-controls information, the arithmetic-controls information, and an instruction resumption record, if one exists. Also to be saved are the previous frame linkage pointer and the contents of the volatile global registers. This copy operation is required because when the interrupted task is resumed at a later time, the original interrupt frame on the interrupt stack, along with its allocated local register set, is no longer accessible.
Generally in a multi-tasking environment, when the higher priority task has completed its execution, and it is time to resume the previously interrupted (preempted) task, the contents of the volatile global registers must be restored, and the normal interrupt return procedure (described previously in this section) must be executed so that the processor context, as well as the task context, can be properly restored.
Maintaining task control blocks and copying data into and out of memory does introduce significant overhead to interrupt handling. This becomes more pronounced in multi-tasking environments under conditions of frequently occurring interrupts.
Interrupt handling, task switching and preemption are the most time-critical areas of code for a multi-tasking operating system, and each unnecessary instruction can degrade system performance. It is therefore highly desirable to develop a method of operation for such a microprocessor where task switching times are reduced as much as possible and the speed of interrupt processing is enhanced.